#include <gtest/gtest.h>

#include <QDataStream>
#include <QCoreApplication>
#include <QUuid>

#include <Type/News.h>

#include <Data/User.h>

#include <Request/NewsQuery.h>
#include <Request/NewsManager.h>

#include <PredefinedConstance/News.h>
#include <CRUDTest.h>

#include "Server.h"
#include "privilege.h"

using namespace std;

std::ostream &operator << (std::ostream &s, TC::Request::AbstractProcedure::Status status);
namespace Request
{
	class News
	{
	public:
		News()
		{
			Server();
		}
	public:
		typedef TCServer::Type::News DataType;
		typedef TC::Request::NewsQuery QueryType;
		typedef TC::Request::NewsManager ManagerType;
	public:
		typedef tuple<bool, QList<DataType>> QueryResult;
		QueryResult query()
		{
			if (!obtainUserPrivilege())
				return make_tuple(true, QList<DataType>());

			QueryType q;
			q.queryAll(testVals.groupId);
			while(q.status() == QueryType::Status::Communicating)
				QCoreApplication::processEvents();

			if (q.status() == QueryType::Status::Ok)
			{
				QList<DataType> res;

				auto vs = q.property("news").toList();
				for (const auto &v : vs)
				{
					res.append(DataType::fromVariantMap(v.toMap()));
				}
				return make_tuple(true, res);
			}
			return make_tuple(true, QList<DataType>());
		}

		typedef bool InsertResult;
		bool insert()
		{
			if (!obtainAdminPrivilege())
				return false;
			ManagerType m;
			m.add(testVals.groupId, testVals.val2insert.toVairantMap());
			while (m.status() == QueryType::Status::Communicating)
				QCoreApplication::processEvents();

			return m.status() == QueryType::Status::Ok;
		}

		typedef bool UpdateResult;
		bool update()
		{
			if (!obtainAdminPrivilege())
				return false;
			ManagerType m;
			m.update(testVals.val2update.toVairantMap());
			while (m.status() == QueryType::Status::Communicating)
				QCoreApplication::processEvents();

			return m.status() == QueryType::Status::Ok;
		}

		typedef bool RemoveResult;
		bool remove()
		{
			if (!obtainAdminPrivilege())
				return false;
			ManagerType m;
			m.remove(testVals.val2update.id);
			while (m.status() == QueryType::Status::Communicating)
				QCoreApplication::processEvents();

			return m.status() == QueryType::Status::Ok;
		}

	public:
		bool isQuerySuccess(const QueryResult & queryResult)
		{
			return get<bool>(queryResult);
		}
		bool checkInsert(const QueryResult &requeryResult)
		{
			const auto &s = get<1>(requeryResult);
			auto it = find(s.begin(), s.end(), testVals.val2insert);
			if (it == s.end())
				return false;
			testVals.val2update.id = it->id;
			testVals.val2insert.id = it->id;
			return true;
		}
		bool checkRemove(const QueryResult &requeryResult)
		{
			const auto &s = get<1>(requeryResult);
			auto it = find_if(s.begin(), s.end(), [this](const DataType &v)
			{
				return v.id == testVals.val2insert.id;
			});
			return it == s.end();
		}
	private:
		PredefinedConstance::News testVals;
	};
}

INSTANTIATE_TYPED_TEST_CASE_P(Request_News, CRUDTest, Request::News);